
package es.aurea.persistence.utils;

import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import javax.persistence.EntityManager;
import javax.persistence.Query;

/**
 * Creador de Querys para JPA.
 *
 * @param <E>
 * @author $Author$ Isaias Cortes (isaias.cortes@espaciosoa.com)
 * @author $Author$
 * @version $Revision$
 * $Id$
 */
public class QueryFactory <E> {

    private final String SELECT = "SELECT";
    private final String DELETE = "DELETE";
    private final String DISTINCT = "DISTINCT";
    private final String COUNT = "COUNT";
    private final String FROM = "FROM";
    private final String INNER_JOIN = "INNER JOIN";
    private final String LEFT_OUTER_JOIN = "LEFT OUTER JOIN";
    private final String IN = "IN";
    private final String WHERE = "WHERE";
    private final String AND = "AND";
    private final String OR = "OR";
    private final String GROUPBY = "GROUP BY";
    private final String ORDERBY = "ORDER BY";
    private final String ASC = "ASC";
    private final String DESC = "DESC";
    private final String COMMA_SEPARE = ", ";
    private final String INIT_PARENTESIS = "(";
    private final String END_PARENTESIS = ")";

    /**
     * Operadores para JPA.
     */
    public enum Operators {

        /**
         * Operador Equal
         */
        EQUAL("="),
        /**
         * Operador Not Equal
         */
        NOT_EQUAL("<>"),
        /**
         * Operador Greater
         */
        GREATER(">"),
        /**
         * Operador Greater_Equal
         */
        GREATER_EQUAL(">="),
        /**
         * Operador Less
         */
        LESS("<"),
        /**
         * Operador Less_Equal
         */
        LESS_EQUAL("<="),
        /**
         * Operador Between
         */
        BETWEEN("BETWEEN"),
        /**
         * Operador In
         */
        IN("IN"),
        /**
         * Operador Is_Null
         */
        IS_NULL("IS NULL"),
        /**
         * Operador Is_Not_Null
         */
        IS_NOT_NULL("IS NOT NULL"),
        /**
         * Operador Like
         */
        LIKE("LIKE"),
        /**
         * Funcion Sum
         */
        SUM("SUM");
        private String value;

        Operators(String operator) {
            this.value = operator;
        }

        /**
         * Devuelve el operador.
         * @return operador.
         */
        public String getOperator() {
            return this.value;
        }
    }
    private String select;
    private boolean delete;
    private boolean distinct;
    private boolean count;
    private String from;
    private String where;
    private String groupBy;
    private String orderBy;
    private int selectNum;
    private int fromNum;
    private int whereNum;
    private int groupByNum;
    private int orderByNum;
    private HashMap<String, Object> values;

    /**
     * Constructor sin parametros de QueryFactory
     */
    public QueryFactory() {
        this.select = "";
        this.delete = false;
        this.distinct = false;
        this.count = false;
        this.from = "";
        this.where = "";
        this.groupBy = "";
        this.orderBy = "";
        this.values = new HashMap<String, Object>();
    }

    /**
     * AÃ±ade al 'SELECT' un objeto, de tipo tabla, como resultado.
     *
     * @param idTable Tabla para JPA
     */
    public void setDelete() {
        this.delete = true;
    }

    /**
     * AÃ±ade al 'SELECT' un objeto, de tipo tabla, como resultado.
     *
     * @param idTable Tabla para JPA
     */
    public void addSelect(String idTable) {
        if (selectNum > 0) {
            select += COMMA_SEPARE;
        }
        select += String.format(" %s ", idTable);
        selectNum++;
    }

    /**
     * AÃ±ade al 'SELECT' un objeto, que es campo de una tabla, como resultado.
     *
     * @param idTable Tabla de JPA
     * @param field campo de JPA
     */
    public void addSelect(String idTable, String field) {
        if (selectNum > 0) {
            select += COMMA_SEPARE;
        }
        select += String.format(" %s.%s ", idTable, field);
        selectNum++;
    }

    /**
     * AÃ±ade al 'SELECT' el parÃ¡metro 'SUM'.
     */
    public void addSelectSum(String idTable) {
        if (selectNum > 0) {
            select += COMMA_SEPARE;
        }
        select += String.format(" %s ", "sum(" + idTable + ")");
        selectNum++;
    }

    /**
     * AÃ±ade al 'SELECT' el parÃ¡metro 'DISTINCT'.
     */
    public void addSelectDistinct() {
        distinct = true;
    }

    /**
     * AÃ±ade al 'SELECT' el parÃ¡metro 'COUNT'.
     */
    public void addSelectCount() {
        count = true;
    }

    /**
     * AÃ±ade al 'FROM' una tabla donde buscar.
     *
     * @param table Tabla de JPA
     * @param idTable Campo id de la Tabla
     */
    public void addFrom(String table, String idTable) {
        if (fromNum > 0) {
            from += COMMA_SEPARE;
        }
        from += String.format(" %s %s ", table, idTable);
        fromNum++;
    }

    /**
     * AÃ±ade al 'FROM' una Inner Join.
     *
     * @param idTable Tabla para realizar un Join
     * @param fieldJoin Campo de la Tabla Principal
     * @param joinId Campo de la Join
     */
    public void addFromInnerJoin(String idTable, String fieldJoin, String joinId) {
        if (fromNum > 0) {
            from += COMMA_SEPARE;
        }
        from += String.format(" %s %s.%s %s", INNER_JOIN, idTable, fieldJoin, joinId);
        fromNum++;
    }

    /**
     * AÃ±ade al 'FROM' una Inner Join.
     *
     * @param idTable Tabla para realizar un Join
     * @param fieldJoin Campo de la Tabla Principal
     * @param joinId Campo de la Join
     */
    public void addFromLeftOuterJoin(String idTable, String fieldJoin, String joinId) {
        if (fromNum > 0) {
            from += COMMA_SEPARE;
        }
        from += String.format(" %s %s.%s %s", LEFT_OUTER_JOIN, idTable, fieldJoin, joinId);
        fromNum++;
    }

    /**
     * AÃ±ade al 'FROM', como tabla, una colecciÃ³n que es parÃ¡metro de otra tabla.
     *
     * @param idTable Tabla de JPA
     * @param collectionField campo para el IN
     * @param idCollection campo id de la coleccion.
     * @throws QueryFactoryException
     */
    public void addFromIN(String idTable, String collectionField, String idCollection) throws QueryFactoryException {
        if (fromNum > 0) {
            from += String.format(COMMA_SEPARE + " %s( %s.%s ) %s ", IN, idTable, collectionField, idCollection);
        } else {
            throw new QueryFactoryException("Unable to define a 'FROM IN' without any first define 'FROM'");
        }
    }

    /**
     * Metodo para AÃ±adir una Tabla
     * @param table1 Tabla 1 JPA
     * @param idTable1 Id de la Tabla 1 JPA
     * @param field1 Campo de la Tabla 1 para el Join
     * @param operator Operador de la Join
     * @param table2 Tabla 2 JPA
     * @param idTable2 Id de la Tabla 2 JPA
     * @param field2 Campo de la Tabla 2 para el Join
     */
    public void addJOIN(String table1, String idTable1, String field1, Operators operator, String table2, String idTable2, String field2) {
        addFrom(table1, idTable1);
        addFrom(table2, idTable2);
        addWhereJOIN(idTable1, field1, operator, idTable2, field2);
    }

    /**
     * Metodo para AÃ±adir un Where a la join
     * @param idTable1 Id de la Tabla 1 JPA
     * @param field1 Campo de la Tabla 1 para el Join
     * @param operator Operador de la Join
     * @param idTable2 Id de la Tabla 2 JPA
     * @param field2 Campo de la Tabla 2 para el Join
     */
    public void addWhereJOIN(String idTable1, String field1, Operators operator, String idTable2, String field2) {
        if (whereNum > 0) {
            where += AND;
        }
        where += String.format(" %s.%s %s %s.%s ", idTable1, field1, operator.getOperator(), idTable2, field2);
        whereNum++;
    }

    /**
     * Metodo para AÃ±adir condiciones a la query
     * @param idTable  Id de la Tabla JPA
     * @param field Campo de la Tabla
     * @param operator Operador de la Condicion
     * @param value  Valor de la condicion.
     */
    public void addWhereAND(String idTable, String field, Operators operator, String value) {
        String parameter = idTable + field;
        parameter = parameter.replaceAll("\\.", "");
        parameter = validateParameter(parameter);
        if (value != null && value.length() > 0) {
            if (whereNum > 0) {
                where += AND;
            }
            where += String.format(" %s.%s %s :%s ", idTable, field, operator.getOperator(), parameter);
            whereNum++;
            this.values.put(parameter, value);
        }
    }

    /**
     * Metodo para AÃ±adir condiciones a la query
     * @param idTable  Id de la Tabla JPA
     * @param field Campo de la Tabla
     * @param operator Operador de la Condicion
     * @param value  Valor de la condicion.
     */
    public void addWhereAND(String idTable, String field, Operators operator, Object value) {
        String parameter = idTable + field;
        parameter = parameter.replaceAll("\\.", "");
        parameter = validateParameter(parameter);
        if (value != null) {
            if (whereNum > 0) {
                where += AND;
            }
            where += String.format(" %s.%s %s :%s ", idTable, field, operator.getOperator(), parameter);
            whereNum++;
            this.values.put(parameter, value);
        }
    }

    /**
     * Metodo para AÃ±adir condiciones a la query
     * @param idTable  Id de la Tabla JPA
     * @param field Campo de la Tabla
     * @param operator Operador de la Condicion
     * @param value  Valor de la condicion.
     */
    public void addWhereInitAND(String idTable, String field, Operators operator, Object value) {
        String parameter = idTable + field;
        parameter = parameter.replaceAll("\\.", "");
        parameter = validateParameter(parameter);
        if (value != null) {
            if (whereNum > 0) {
                where += AND;
            }
            where += String.format(" %s%s.%s %s :%s ", INIT_PARENTESIS, idTable, field, operator.getOperator(), parameter);
            whereNum++;
            this.values.put(parameter, value);
        }
    }

    /**
     * Metodo para AÃ±adir condiciones a la query
     * @param idTable  Id de la Tabla JPA
     * @param field Campo de la Tabla
     * @param operator Operador de la Condicion
     * @param value  Valor de la condicion.
     */
    public void addWhereEndAND(String idTable, String field, Operators operator, Object value) {
        String parameter = idTable + field;
        parameter = parameter.replaceAll("\\.", "");
        parameter = validateParameter(parameter);
        if (value != null) {
            if (whereNum > 0) {
                where += AND;
            }
            where += String.format(" %s.%s %s :%s%s ", idTable, field, operator.getOperator(), parameter, END_PARENTESIS);
            whereNum++;
            this.values.put(parameter, value);
        }
    }

    /**
     * Metodo para preguntar si la condicion es null
     * @param idTable Tabla para la condicion.
     * @param field Campo a preguntar por Null
     */
    public void addIsNullAND(String idTable, String field) {
        String parameter = idTable + field;
        parameter = parameter.replaceAll("\\.", "");
        parameter = validateParameter(parameter);
        if (whereNum > 0) {
            where += AND;
        }
        where += String.format(" %s.%s %s ", idTable, field, Operators.IS_NULL.getOperator());
        whereNum++;
    }

    /**
     * Metodo para preguntar si la condicion es null
     * @param idTable Tabla para la condicion.
     * @param field Campo a preguntar por Null
     */
    public void addIsNullOR(String idTable, String field) {
        String parameter = idTable + field;
        parameter = parameter.replaceAll("\\.", "");
        parameter = validateParameter(parameter);
        if (whereNum > 0) {
            where += OR;
        }
        where += String.format(" %s.%s %s ", idTable, field, Operators.IS_NULL.getOperator());
        whereNum++;
    }

    /**
     * Metodo para preguntar si la condicion no es null
     * @param idTable Tabla para la condicion.
     * @param field Campo a preguntar por Null
     */
    public void addIsNotNullAND(String idTable, String field) {
        String parameter = idTable + field;
        parameter = parameter.replaceAll("\\.", "");
        parameter = validateParameter(parameter);
        if (whereNum > 0) {
            where += AND;
        }
        where += String.format(" %s.%s %s ", idTable, field, Operators.IS_NOT_NULL.getOperator());
        whereNum++;
    }

    /**
     * Metodo para preguntar si la condicion no es null
     * @param idTable Tabla para la condicion.
     * @param field Campo a preguntar por Null
     */
    public void addIsNotNullOR(String idTable, String field) {
        String parameter = idTable + field;
        parameter = parameter.replaceAll("\\.", "");
        parameter = validateParameter(parameter);
        if (whereNum > 0) {
            where += OR;
        }
        where += String.format(" %s.%s %s ", idTable, field, Operators.IS_NOT_NULL.getOperator());
        whereNum++;
    }

    /**
     * Metodo para AÃ±adir condiciones a la query de tipo AND
     * @param idTable1  Id de la Tabla 1 JPA
     * @param field1 Campo de la Tabla 1.
     * @param operator Operador de la Condicion
     * @param idTable2 Id de la Tabla 2 JPA
     * @param field2 Campo de la Tabla 2.
     */
    public void addWhereAND(String idTable1, String field1, Operators operator, String idTable2, String field2) {
        if (whereNum > 0) {
            where += AND;
        }
        where += String.format(" %s.%s %s %s.%s ", idTable1, field1, operator.getOperator(), idTable2, field2);
        whereNum++;
    }

    /**
     * Metodo para AÃ±adir condiciones a la query de tipo OR
     * @param idTable1  Id de la Tabla 1 JPA
     * @param field1 Campo de la Tabla 1.
     * @param operator Operador de la Condicion
     * @param idTable2 Id de la Tabla 2 JPA
     * @param field2 Campo de la Tabla 2.
     */
    public void addWhereOR(String idTable1, String field1, Operators operator, String idTable2, String field2) {
        if (whereNum > 0) {
            where += OR;
        }
        where += String.format(" %s.%s %s %s.%s ", idTable1, field1, operator.getOperator(), idTable1, field1);
        whereNum++;
    }

    private String validateParameter(String parameter) {
        int num = 0;
        String parameterName = parameter;
        while (this.values.get(parameterName) != null) {
            num++;
            parameterName = parameter + num;
        }
        return parameterName;
    }

    /**
     * Metodo para AÃ±adir condiciones a la query de tipo OR
     * @param idTable  Id de la Tabla JPA
     * @param field Campo de la Tabla.
     * @param operator Operador de la Condicion
     * @param value Valor de la Condicion.
     */
    public void addWhereOR(String idTable, String field, Operators operator, String value) {
        String parameter = idTable + field;
        parameter = parameter.replaceAll("\\.", "");
        parameter = validateParameter(parameter);
        if (value != null && value.length() > 0) {
            if (whereNum > 0) {
                where += OR;
            }
            where += String.format(" %s.%s %s :%s ", idTable, field, operator.getOperator(), parameter);
            whereNum++;
            this.values.put(parameter, value);
        }
    }

    /**
     * Metodo para AÃ±adir condiciones a la query de tipo OR
     * @param idTable  Id de la Tabla JPA
     * @param field Campo de la Tabla.
     * @param operator Operador de la Condicion
     * @param value Valor de la Condicion.
     */
    public void addWhereOR(String idTable, String field, Operators operator, Object value) {
        String parameter = idTable + field;
        parameter = parameter.replaceAll("\\.", "");
        parameter = validateParameter(parameter);
        if (value != null) {
            if (whereNum > 0) {
                where += OR;
            }
            where += String.format(" %s.%s %s :%s ", idTable, field, operator.getOperator(), parameter);
            whereNum++;
            this.values.put(parameter, value);
        }
    }

    /**
     * Metodo para AÃ±adir condiciones a la query de tipo OR
     * @param idTable  Id de la Tabla JPA
     * @param field Campo de la Tabla.
     * @param operator Operador de la Condicion
     * @param value Valor de la Condicion.
     */
    public void addWhereInitOR(String idTable, String field, Operators operator, Object value) {
        String parameter = idTable + field;
        parameter = parameter.replaceAll("\\.", "");
        parameter = validateParameter(parameter);
        if (value != null) {
            if (whereNum > 0) {
                where += OR;
            }
            where += String.format(" %s%s.%s %s :%s ", INIT_PARENTESIS, idTable, field, operator.getOperator(), parameter);
            whereNum++;
            this.values.put(parameter, value);
        }
    }

    /**
     * Metodo para AÃ±adir condiciones a la query de tipo OR
     * @param idTable  Id de la Tabla JPA
     * @param field Campo de la Tabla.
     * @param operator Operador de la Condicion
     * @param value Valor de la Condicion.
     */
    public void addWhereEndOR(String idTable, String field, Operators operator, Object value) {
        String parameter = idTable + field;
        parameter = parameter.replaceAll("\\.", "");
        parameter = validateParameter(parameter);
        if (value != null) {
            if (whereNum > 0) {
                where += OR;
            }
            where += String.format(" %s.%s %s :%s%s ", idTable, field, operator.getOperator(), parameter, END_PARENTESIS);
            whereNum++;
            this.values.put(parameter, value);
        }
    }

    /**
     * Metodo para aÃ±adir condiciones de tipo Where y Between.
     * @param idTable Tabla de JPA
     * @param field Campo de la Tabla
     * @param value1 Valor 1
     * @param value2 Valor 2
     */
    private void addWhereBETWEEN(String idTable, String field, Date value1, Date value2, String union) {
        String parameter1 = idTable + field + "1";
        String parameter2 = idTable + field + "2";
        parameter1 = parameter1.replaceAll("\\.", "");
        parameter2 = parameter2.replaceAll("\\.", "");
        parameter1 = validateParameter(parameter1);
        parameter2 = validateParameter(parameter2);
        if (value1 != null && value2 != null) {
            if (whereNum > 0) {
                where += union;
            }
            where += String.format(" %s.%s %s :%s %s :%s ", idTable, field, Operators.BETWEEN.getOperator(), parameter1, AND, parameter2);
            whereNum++;
            this.values.put(parameter1, value1);
            this.values.put(parameter2, value2);
        } else if (value1 != null) {
            if (whereNum > 0) {
                where += union;
            }
            where += String.format(" %s.%s %s :%s ", idTable, field, Operators.GREATER_EQUAL.getOperator(), parameter1);
            whereNum++;
            this.values.put(parameter1, value1);
        } else if (value2 != null) {
            if (whereNum > 0) {
                where += union;
            }
            where += String.format(" %s.%s %s :%s ", idTable, field, Operators.LESS_EQUAL.getOperator(), parameter2);
            whereNum++;
            this.values.put(parameter2, value2);
        }
    }

    /**
     * Metodo para aÃ±adir condiciones de tipo Where y Between.
     * @param idTable Tabla de JPA
     * @param field Campo de la Tabla
     * @param value1 Valor 1
     * @param value2 Valor 2
     */
    public void addWhereANDBETWEEN(String idTable, String field, Date value1, Date value2) {
        addWhereBETWEEN(idTable, field, value1, value2, AND);
    }

    /**
     * Metodo para aÃ±adir condiciones de tipo Where y Between.
     * @param idTable Tabla de JPA
     * @param field Campo de la Tabla
     * @param value1 Valor 1
     * @param value2 Valor 2
     */
    public void addWhereORBETWEEN(String idTable, String field, Date value1, Date value2) {
        addWhereBETWEEN(idTable, field, value1, value2, OR);
    }

    /**
     * Metodo para aÃ±adir condiciones de tipo IN
     * @param idTable Tabla de JPA
     * @param field Campo de la Tabla
     * @param values Valores del In
     */
    public void addWhereANDIN(String idTable, String field, ArrayList values) {
        if (values != null && values.size() > 0) {
            if (whereNum > 0) {
                where += AND;
            }
            where += String.format(" %s.%s %s( ", idTable, field, Operators.IN.getOperator());
            int x = 1;
            for (Object value : values) {
                if (x > 1) {
                    where += " , ";
                }
                String parameter = idTable + field + x++;
                parameter = parameter.replaceAll("\\.", "");
                parameter = validateParameter(parameter);
                where += String.format(" :%s ", parameter);
                this.values.put(parameter, value);
            }
            where += " ) ";
            whereNum++;
        }
    }

//    /**
//     *
//     * @param idTable
//     * @param field
//     * @param subselect
//     * @param operator
//     * s.statusDate = (SELECT max(csc.statusDate) FROM CommunicationStatusCommcsc. ion csc WHERE "
//     */
//    public void addWhereSubselect(String idTable, String field, String operator, String subselect) {
//        String parameter = idTable + field;
//        if (whereNum > 0) {
//            where += OR;
//        }
//        where += String.format(" %s.%s %s :%s", idTable, field, operator, parameter);
//        whereNum++;
//        this.values.put(parameter, value);
//
//        if (whereNum++ == 0) {
//            where = String.format(" WHERE %s.%s %s ( " + subselect + ")", idTable, field, operator);
//        } else {
//            where += String.format(" AND %s.%s %s ( " + subselect + ")", idTable, field, operator);
//        }
//    }
    /**
     * Metodo para Ordenar la Query por una tabla y un campo.
     * @param idTable Tabla JPA
     * @param field Campo de Ordenacion
     */
    public void addOrderByASC(String idTable, String field) {
        if (orderByNum > 0) {
            orderBy += COMMA_SEPARE;
        }
        orderBy += String.format(" %s.%s %s ", idTable, field, ASC);
        orderByNum++;
    }


    public void addGroupBy(String idTable, String field) {
        if (groupByNum > 0) {
            groupBy += COMMA_SEPARE;
        }
        groupBy += String.format(" %s %s.%s ", GROUPBY, idTable, field);
        groupByNum++;
    }

    /**
     * Metodo para Ordenar la Query por una tabla y un campo.
     * @param idTable Tabla JPA
     * @param field Campo de Ordenacion
     */
    public void addOrderByDESC(String idTable, String field) {
        if (orderByNum > 0) {
            orderBy += COMMA_SEPARE;
        }
        orderBy += String.format(" %s.%s %s ", idTable, field, DESC);
        orderByNum++;
    }

    /**
     * Metodo para generar la query
     * @return Retorna la Query
     * @throws QueryFactoryException  Si hay algun problema en la operacion.
     */
    public String generateQuery() throws QueryFactoryException {
        String query = null;
        if (delete) {
            query = String.format("%s", DELETE);
        } else if (selectNum > 0) {
            query = String.format("%s %s %s %s %s", SELECT, (count) ? COUNT + "(" : "", (distinct) ? DISTINCT : "", select, (count) ? ")" : "");
        } else {
            throw new QueryFactoryException("No SELECT defined.");
        }
        if (fromNum > 0) {
            query = String.format("%s %s %s", query, FROM, from);
        } else {
            throw new QueryFactoryException("No FROM defined.");
        }
        if (whereNum > 0) {
            query = String.format("%s %s %s", query, WHERE, where);
        }
        if (groupByNum > 0) {
            query = String.format("%s %s %s", query, GROUPBY, groupBy);
        }
        if (orderByNum > 0 && !count) {
            query = String.format("%s %s %s", query, ORDERBY, orderBy);
        }
        // System.out.println("GeneratedQuery: " + query);
        return query;
    }

    /**
     *
     * @param em Entity Manager.
     * @return Query Generada.
     * @throws QueryFactoryException Si hay algun problema en la operacion.
     */
    public Query generateQuery(EntityManager em) throws QueryFactoryException {
        Query query = em.createQuery(generateQuery());
        Iterator iterator = values.entrySet().iterator();
        while (iterator.hasNext()) {
            Map.Entry e = (Map.Entry) iterator.next();
            query.setParameter(e.getKey().toString(), e.getValue());
        }
        return query;
    }

    /**
     * Metodo que devuelve un unico registro con la consulta preparada.
     * @param em Entity Manager.
     * @return Entidad Unica encontrada.
     * @throws QueryFactoryException  Si hay algun problema en la operacion.
     */
    public E getSingleResult(EntityManager em) throws QueryFactoryException {
        try {
            return (E) generateQuery(em).getSingleResult();
        } catch (Throwable e) {
            throw new QueryFactoryException(e.getMessage());
        }
    }

    /**
     * Metodo que devuelve la consultar preparada.
     * @param em Entity Manager
     * @return Array con Entidades encontradas.
     * @throws QueryFactoryException  Si hay algun problema en la operacion.
     */
    @SuppressWarnings("unchecked")
    public List<E> getResultList(EntityManager em) throws QueryFactoryException {
        try {
            return (List<E>) generateQuery(em).getResultList();
        } catch (Throwable e) {
            throw new QueryFactoryException(e.getMessage());
        }
    }

    /**
     * <b>Description:</b> Obtien lso parametros de la query para imprimirlos.
     * @return un string para visualizar los parÃ¡metros de la query.
     */
    public String printParameters() {

        String results = "";

        Set set = values.entrySet();
        Iterator iter = set.iterator();

        while (iter.hasNext()) {
            Map.Entry entry = (Map.Entry) iter.next();
            results += "[" + entry.getKey() + "=" + entry.getValue() + "] ";
        }

        return results;

    }
}
